package service

import (
	"encoding/json"
	"fmt"
	"im-demo/application/model"
	"im-demo/util"
	"time"
)

// 管理员，负责管理client
type Manager struct {
	Clients    map[string]*Client // 客户端列表
	Register   chan *Client       // 注册器，当有新连接时，注册到客户端列表
	Unregister chan *Client       // 注销器，发现有连接断开时，将其从客户端列表中移除
	MsgBuff    chan []byte        // 入站消息队列
}

func NewManager() *Manager {
	return &Manager{
		Clients:    make(map[string]*Client),
		Register:   make(chan *Client),
		Unregister: make(chan *Client),
		MsgBuff:    make(chan []byte),
	}
}

// Run 启动管理
func (m *Manager) Run() {
	for {
		select {
		case client := <-m.Register: // 注册
			m.Clients[client.Uid] = client
		case client := <-m.Unregister: // 注销
			if _, ok := m.Clients[client.Uid]; ok {
				delete(m.Clients, client.Uid)
				close(client.Send)
			}
		case msg := <-m.MsgBuff:
			var message model.Message
			if err := json.Unmarshal(msg, &message); err != nil {
				fmt.Println("消息解析失败：", string(msg))
				break
			}

			// 获取消息id和当前时间戳
			MsgId, err := util.MakeSnowflakeID()
			if err != nil {
				fmt.Println("get snowflake id fail")
				break
			}
			curTime := time.Now().Unix()
			message.MsgId = MsgId
			message.CreateTime = curTime

			// 重新封装消息
			msg, err = json.Marshal(message)
			if err != nil {
				fmt.Println("marshal message fail")
				break
			}

			// 更新会话列表
			// update last_time、last_msg_id、last_msg
			update := model.UpdateData{
				OwnerId:   message.OwnerId,
				OtherId:   message.OtherId,
				LastTime:  curTime,
				LastMsgId: MsgId,
				LastMsg:   message,
			}
			err = model.UpdateSession(&update)
			if err != nil {
				fmt.Println("Fail to update Session," + err.Error())
			}

			// 给自己发送封装后的消息
			if client, ok := m.Clients[message.OwnerId]; ok {
				client.Send <- msg
			}

			// 给对方发送封装后的消息
			// 对方在线，直接发送；对方不在线，存储为离线消息，对应会话未读消息+1
			if client, ok := m.Clients[message.OtherId]; ok {
				client.Send <- msg
			} else {
				fmt.Println("other down")

				_, err = model.CreateMsg(&message)
				if err != nil {
					fmt.Println("storage message fail")
					break
				}

				_, err = model.IncUnreadMsgCount(message.OtherId, message.OwnerId)
				if err != nil {
					fmt.Println("inc unread message fail")
					break
				}
			}
		}
	}
}
